home *** CD-ROM | disk | FTP | other *** search
/ Best Tools for JAVA / Best Tools for JAVA.iso / JAVA_ALL / IDE / SUBARTIC / SUB_ARCT / LIB / MULTI_BU.JAV < prev    next >
Encoding:
Text File  |  1996-10-04  |  18.3 KB  |  593 lines

  1. package sub_arctic.lib;
  2.  
  3. import sub_arctic.input.event;
  4. import sub_arctic.input.callback_object;
  5. import sub_arctic.input.inout_draggable;
  6. import sub_arctic.input.pressable;
  7.  
  8. import sub_arctic.output.color_pair;
  9. import sub_arctic.output.loaded_image;
  10. import sub_arctic.output.drawable;
  11.  
  12. import sub_arctic.lib.sub_arctic_error;
  13.  
  14. import java.awt.Point;
  15. import java.awt.Dimension;
  16. import java.awt.Image;
  17. import java.awt.Font;
  18. import java.awt.FontMetrics;
  19. import java.awt.Color;
  20.  
  21. /**
  22.  * This class implements a multi-state button object. It can have any
  23.  * number of states and may have transitions between those states with
  24.  * individual looks.
  25.  * 
  26.  * @author Scott Hudson
  27.  */
  28. public class multi_button extends base_interactor 
  29.   implements inout_draggable, pressable {
  30.  
  31.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  32.  
  33.   /** 
  34.    * Full constructor.  The two image sets provided give normal appearance
  35.    * for each state of the button, and a transition appearance out of each
  36.    * state of the button.  The transition set may be coded as null in which
  37.    * case the next state image is used when a transition is needed.  Otherwise
  38.    * the two image sets must be the same size.
  39.    * 
  40.    * @param int             x           x position of this object
  41.    * @param int             y           y position of this object
  42.    * @param loaded_image[]  st_looks    the set of images for the looks of this 
  43.    *                                    object
  44.    * @param loaded_image[]  trans_looks the set of images for the looks of 
  45.    *                                    transitions of this object.
  46.    * @param callback_object call_obj    the object to send the callbacks to.
  47.    */
  48.   public multi_button(
  49.     int              x,
  50.     int              y,
  51.     loaded_image[]   st_looks, 
  52.     loaded_image[]   trans_looks, 
  53.     callback_object  call_obj) 
  54. {
  55.       super(x,y);
  56.  
  57.       /* if the st_looks is null, we allow that because subclasses
  58.        * may not yet have had time to compute the images for the 
  59.        * buttons
  60.        */
  61.  
  62.       /* check for transitions not being the right size */
  63.       if (trans_looks != null && trans_looks.length != st_looks.length)
  64.     throw new sub_arctic_error("Normal and transition image sets of "+
  65.                    "unequal size passed to multi_button()");
  66.  
  67.       /* save the instance vars */
  68.       set_looks(st_looks, trans_looks);
  69.       _callback_obj   = call_obj;
  70.  
  71.       /* initially in state 0 and not in transition */
  72.       _cur_state = 0;
  73.       _in_transition = false;
  74.  
  75.       /* calculate correct initial size */
  76.       calc_size();
  77.     }
  78.  
  79.    //had:
  80.    //* @exception bad_value thrown if the set of images passed in are not of a 
  81.    //*                      legitimate size or the number of transitions is 
  82.    //*                      different from the number of states
  83.    //* @exception general PROPAGATED
  84.  
  85.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  86.  
  87.   /** 
  88.    * This interactor determines width and height internally, and does not
  89.    * intrinsically constrain part_a. 
  90.    * @return int the constant mask for an internal width and height
  91.    */
  92.   public int intrinsic_constraints() 
  93.     { 
  94.       /* take part_a out and put w & h in */
  95.       return (super.intrinsic_constraints() & ~PART_A) | W | H; 
  96.     }
  97.  
  98.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  99.  
  100.   /** 
  101.    * Internal indicator of whether we are currently in transition from 
  102.    * one state to the next.
  103.    */
  104.   protected boolean _in_transition = false;
  105.  
  106.   /** 
  107.    * Index of current state. 
  108.    */
  109.   protected int _cur_state = 0;
  110.  
  111.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  112.  
  113.   /** 
  114.    * Return the value of the part_a component of this object.  In our case 
  115.    * this is stored in _cur_state. 
  116.    */
  117.   public int part_a()
  118.     {
  119.       /* Make sure its up to date then return it */
  120.       eval_part_a();
  121.       return _cur_state;
  122.     }
  123.  
  124.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  125.  
  126.   /** 
  127.    * Set part_a value directly bypassing the constraint system (but doing 
  128.    * damage). In this case part_a is stored in _cur_state.
  129.    * 
  130.    * @param int v the new value for part_a.
  131.    */
  132.   protected void set_raw_part_a(int v) 
  133. {
  134.       /* force v in range */
  135.       if (v < 0) v = 0;
  136.       if (v >= state_looks().length) v = state_looks().length-1;
  137.  
  138.       /* don't do anything unless this is a change */
  139.       if (v != _cur_state)
  140.     {
  141.       /* make change and do damage */
  142.           _cur_state = v;
  143.           damage_self();
  144.     }
  145.     }
  146.  
  147.    //had:
  148.    //* @exception general
  149.  
  150.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  151.  
  152.   /** 
  153.    * Set the part_a component of this object.  In our case this is stored in
  154.    * _cur_state.  
  155.    *
  156.    * @param int v the new value of part_a.
  157.    */
  158.   public void set_part_a(int v) 
  159. {
  160.       /* if this has a constraint throw an exception */
  161.       if ((active_constraints() & PART_A) != 0)
  162.         throw new sub_arctic_error(
  163.       "Attempt to assign value to constrained part_a (AKA cur_state)");
  164.  
  165.       /* don't do anything unless this is a change */
  166.       if (v != _cur_state)
  167.     {
  168.       set_raw_part_a(v);
  169.       mark_part_a_ood();
  170.     }
  171.     }
  172.  
  173.    //had:
  174.    //* @exception cannot_assign if part_a has a constraint attached to it.
  175.    //* @exception general
  176.  
  177.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  178.  
  179.   /** 
  180.    * Index of current state.  For toggles, "off" or "unchecked" is zero.
  181.    * The object starts in state 0 by default.  This is mirrored as part_a
  182.    * for this object.
  183.    *
  184.    * @return int the current state from 0 to n-1
  185.    */
  186.   public int cur_state() 
  187.     {
  188.       return part_a();
  189.     }
  190.  
  191.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  192.  
  193.   /**  
  194.    * Set index of current state.  For toggles, "off" or "unchecked" is zero. 
  195.    * This is mirrored as part_a for this object.
  196.    *
  197.    * @param int the new current state.
  198.    */
  199.   public void set_cur_state(int st) 
  200.     {
  201.       set_part_a(st);
  202.     }
  203.  
  204.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  205.  
  206.   /** 
  207.    * Indicate what the next state will be.  Be default we just increment
  208.    * wrapping back to zero as needed.  
  209.    *
  210.    * @return int the next state.
  211.    */
  212.   public int next_state()
  213.     {
  214.       return (cur_state() + 1) % state_looks().length;
  215.     }
  216.  
  217.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  218.  
  219.   /** Image set for "normal" appearance in each state.  */
  220.   protected loaded_image[] _state_looks;
  221.  
  222.   /** 
  223.    * Image set for "normal" appearance in each state.  
  224.    *@return the array of images for the normal states
  225.    */
  226.   public loaded_image[] state_looks() {return _state_looks;}
  227.  
  228.   /** 
  229.    * Get the "normal" appearance image for a given state. 
  230.    * @parm int the state to retrieve the image for
  231.    * @return loaded_image the image for the asked for state
  232.    */
  233.   public loaded_image get_state_look(int indx) {return _state_looks[indx]; }
  234.  
  235.   /** 
  236.    * Set the "normal" appearance image for a given state. 
  237.    * @param int index the state being modified
  238.    * @param int loaded_image img the new image to use for this state
  239.    */
  240.   public void set_state_look(int indx, loaded_image img)
  241.     {
  242.       /* set the image */
  243.       _state_looks[indx] = img;
  244.  
  245.       /* force size recalc */
  246.       calc_size();
  247.     }
  248.  
  249.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  250.  
  251.   /** 
  252.    * Image set for "transition" appearance from each state.  
  253.    */
  254.   protected loaded_image[] _transition_looks;
  255.  
  256.   /** 
  257.    * Image set for "transition" appearance from each state.   
  258.    * @return loaded_image the set of images for the transitions
  259.    */
  260.   public loaded_image[] transition_looks() {return _transition_looks;}
  261.  
  262.   /** 
  263.    * Get the "transition" appearance image from a given state. 
  264.    * @param int indx the state transition of interest
  265.    * @return loaded_image the image for the given state
  266.    */
  267.   public loaded_image get_transition_look(int indx) 
  268.     {
  269.       return _transition_looks[indx]; 
  270.     }
  271.  
  272.   /** 
  273.    * Set the "transition" appearance image from a given state. 
  274.    * @param int          indx the index of the transition to be modified
  275.    * @param loaded_image img  the new image to use for that transition
  276.    */
  277.   public void set_transition_look(int indx, loaded_image img)
  278.     {
  279.       /* set the image */
  280.       _transition_looks[indx] = img;
  281.  
  282.       /* force size recalc */
  283.       calc_size();
  284.     }
  285.  
  286.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  287.  
  288.   /** 
  289.    * Set both "normal" and "transition" image sets.  The normal image for
  290.    * each state is displayed when the button is quiescent in that state.
  291.    * The transition image is shown when the mouse button has been depressed
  292.    * over the button and releasing it would cause a transition to the next
  293.    * state.  The transition set may be coded as null in which
  294.    * case the next state image is used when a transition is needed.  Otherwise
  295.    * the two image sets must be the same size.  
  296.    * 
  297.    * @param loaded_image[] st_looks    the looks for the states.
  298.    * @param loaded_image[] trans_looks the looks for the transitions.
  299.    */
  300.   public void set_looks(loaded_image[] st_looks, loaded_image[] trans_looks) 
  301. {
  302.  
  303.       /* we allow the set of looks to be null so that they can be
  304.      used as placeholds for a later change */
  305.  
  306.       /* check for the set of transitions being the right size */
  307.       if (trans_looks != null && trans_looks.length != st_looks.length)
  308.     throw new sub_arctic_error("Normal and transition image sets "+
  309.                    "of unequal size passed to set_looks()");
  310.  
  311.       /* save the instance vars */
  312.       _state_looks = st_looks;
  313.       _transition_looks = trans_looks;
  314.  
  315.       /* recalculate new sizes */
  316.       calc_size();
  317.     }
  318.  
  319.    //had:
  320.    //* @exception bad_value thrown if the set of images passed in are not of a 
  321.    //*                      legitimate size or the number of transitions is 
  322.    //*                      different from the number of states.
  323.    //* @exception general PROPAGATED
  324.  
  325.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  326.  
  327.   /** Object we make callbacks to */
  328.   protected callback_object _callback_obj;
  329.  
  330.   /** 
  331.    * Object that this button makes callbacks to when pressed.  All callbacks 
  332.    * have a callback number of 0 and the callback_info field contains an
  333.    * Integer object indicating the new state of the button.
  334.    * 
  335.    * @return callback_object the object to send the callbacks to
  336.    */
  337.   public callback_object callback_obj() {return _callback_obj;}
  338.  
  339.   /** 
  340.    * Set the callback object that this button makes callbacks to when pressed.
  341.    * All callbacks have a callback number of 0 and the callback_info field 
  342.    * contains an Integer object indicating the new state of the button.
  343.    * 
  344.    * @param callback_object the new receiver of callbacks
  345.    */
  346.   public void set_callback_obj(callback_object cb) {_callback_obj = cb;}
  347.  
  348.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  349.  
  350.   /** (Re)calculate size as max of images. */
  351.   protected void calc_size()
  352.     {
  353.       int       max_w = 0;
  354.       int       max_h = 0;
  355.  
  356.       /* if you don't have any images, we make you 10x10 */
  357.       if (_state_looks==null) {
  358.     max_w=10;
  359.     max_h=10;
  360.     set_intrinsic_size(max_w, max_h);
  361.     return;
  362.       }
  363.  
  364.       /* calculate max of state appearance images */
  365.       for (int i = 0; i < _state_looks.length; i++)
  366.     if (state_looks()[i] != null)
  367.       {
  368.         if (state_looks()[i].width()> max_w) 
  369.           max_w = state_looks()[i].width();
  370.         if (state_looks()[i].height() > max_h) 
  371.           max_h = state_looks()[i].height();
  372.       }
  373.  
  374.       /* if we have transition images, consider those also */
  375.       if (transition_looks() != null)
  376.         for (int i = 0; i < _state_looks.length; i++)
  377.       if (transition_looks()[i] != null)
  378.         {
  379.           if (transition_looks()[i].width()> max_w) 
  380.             max_w = transition_looks()[i].width();
  381.           if (transition_looks()[i].height() > max_h) 
  382.             max_h = transition_looks()[i].height();
  383.         }
  384.  
  385.        /* if the size changes, reset it */
  386.        if (max_w != w() || max_h != h())
  387.      set_intrinsic_size(max_w, max_h);
  388.     }
  389.  
  390.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  391.  
  392.   /** 
  393.    * Handle mouse presses in our bounds.  This makes us the inout drag 
  394.    * focus (most of the work is handled via the inout_drag protocol. 
  395.    * 
  396.    * @param event  evt       the event to be dispatched.
  397.    * @param Object user_info the object passed to the pick_collector at pick 
  398.    *                         time.
  399.    * @return boolean true if this event has been handled.
  400.    */
  401.   public boolean press(event evt, Object user_info)
  402.     {
  403.       /* make us the inout drag focus */
  404.       manager.inout_drag_focus.set_focus_to(this, evt, user_info);
  405.       return true;
  406.     }
  407.  
  408.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  409.  
  410.   /** 
  411.    * Companion for press() -- ignore here. 
  412.    * @param event  evt       the event to be dispatched.
  413.    * @param Object user_info the object passed to the pick_collector at pick 
  414.    *                         time.
  415.    * @return boolean true if this event has been handled.
  416.    */
  417.   public boolean release(event evt, Object user_info) 
  418.     { 
  419.       return false; 
  420.     }
  421.  
  422.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  423.  
  424.   /** 
  425.    * Handle input corresponding to the start of an inout tracking drag. 
  426.    *
  427.    * @param event   evt           the event to be dispatched
  428.    * @param boolean starts_inside true if the drag starts inside the object
  429.    * @param Object  user_info     the object passed to the inout_drag agent 
  430.    *                              when this object came into the focus set.
  431.    * @return boolean true if this event has been handled
  432.    */
  433.   public boolean inout_drag_start(
  434.     event            evt, 
  435.     boolean          starts_inside,
  436.     Object           user_info) 
  437. {
  438.       /* if we start inside then we are now in transition */
  439.       _in_transition = starts_inside;
  440.       damage_self();
  441.  
  442.       return true;
  443.     }
  444.  
  445.    //had:
  446.    //* @exception general PROPAGATED
  447.  
  448.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  449.  
  450.   /** 
  451.    * Handle "drag" into the bounds of the object. 
  452.    * @param event  evt       the event to be dispatched
  453.    * @param Object user_info the object passed to the inout_drag agent when 
  454.    *                         this object came into the focus set.
  455.    * @return boolean true if this event has been handled
  456.    */
  457.   public boolean inout_drag_enter(event evt, Object user_info) 
  458. {
  459.       /* change appearance and arrange for redraw */
  460.       _in_transition = true;
  461.       damage_self();
  462.  
  463.       return true;
  464.     }
  465.  
  466.    //had:
  467.    //* @exception general PROPAGATED
  468.  
  469.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  470.  
  471.   /** 
  472.    * Handle "drag" out of the bounds of the object. 
  473.    *
  474.    * @param event  evt       the event to be dispatched.
  475.    * @param Object user_info the object passed to the inout_drag agent when 
  476.    *                         this object came into the focus set.
  477.    * @return boolean true if this event has been handled
  478.    */
  479.   public boolean inout_drag_exit(event evt, Object user_info) 
  480. {
  481.       /* change appearance and arrange for redraw */
  482.       _in_transition = false;
  483.       damage_self();
  484.  
  485.       return true;
  486.     }
  487.  
  488.    //had:
  489.    //* @exception general PROPAGATED
  490.  
  491.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  492.  
  493.   /** Callback number constant for the button state transition callback. */
  494.   public static final int BUTTON_ACTION_CALLBACK = 0;
  495.  
  496.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  497.  
  498.   /**  
  499.    * Invoke the callback object.  This is basically here as a hook for 
  500.    * subclasses to override if they would prefer to do something other
  501.    * than a normal callback.
  502.    * @param event evt the event causing the callback
  503.    */
  504.   protected void do_callback(event evt)
  505.     {
  506.       if (callback_obj() != null)
  507.     callback_obj().callback(this, evt, BUTTON_ACTION_CALLBACK, 
  508.                              new Integer(cur_state()));
  509.     }
  510.  
  511.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  512.  
  513.   /** 
  514.    * Handle input corresponding to the end of an inout drag.  Invokes the 
  515.    *  callback if we ended up inside the object.
  516.    * @param event   evt          the event to be dispatched.
  517.    * @param boolean ended_inside true if the drag ended inside the object.
  518.    * @param Object  user_info    the object passed to the inout_drag agent 
  519.    *                             when this object came into the focus set.
  520.    * @return boolean true if this event has been handled
  521.    */
  522.   public boolean inout_drag_end(
  523.     event    evt, 
  524.     boolean  ended_inside, 
  525.     Object   user_info) 
  526. {
  527.       /* if we ended up inside go to new state, do the callback, then redraw */
  528.       if (ended_inside) 
  529.     {
  530.       _in_transition = false;
  531.       set_cur_state(next_state());
  532.       do_callback(evt);
  533.       damage_self();
  534.     }
  535.  
  536.       return true;
  537.     }
  538.  
  539.    //had:
  540.    //* @exception general PROPAGATED
  541.  
  542.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  543.  
  544.   /** 
  545.    * Draw the button 
  546.    * @param drawable d the surface to draw the object on
  547.    */
  548.   protected void draw_self_local(drawable d) 
  549. {
  550.       /* if you don't have any state looks, something is probably wrong */
  551.       if (_state_looks==null) {
  552.     return;
  553.       }
  554.  
  555.       /* if we are in transition then draw the transition look */
  556.       if (_in_transition)
  557.         {
  558.       /* if we have transition look from this state use it */
  559.           if (transition_looks()!=null && transition_looks()[cur_state()]!=null)
  560.             d.drawImage(transition_looks()[cur_state()],0,0);
  561.           else
  562.         /* otherwise use normal look of the next state */
  563.             d.drawImage(state_looks()[next_state()], 0,0);
  564.         }
  565.       else
  566.        {
  567.      /* use normal appearance for current state */
  568.          d.drawImage(state_looks()[cur_state()],0,0);
  569.        }
  570.     }
  571.  
  572.    //had:
  573.    //* @exception general PROPAGATED
  574.  
  575.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  576. }
  577. /*=========================== COPYRIGHT NOTICE ===========================
  578.  
  579. This file is part of the subArctic user interface toolkit.
  580.  
  581. Copyright (c) 1996 Scott Hudson and Ian Smith
  582. All rights reserved.
  583.  
  584. The subArctic system is freely available for most uses under the terms
  585. and conditions described in 
  586.   http://www.cc.gatech.edu/gvu/ui/sub_arctic/sub_arctic/doc/usage.html 
  587. and appearing in full in the lib/interactor.java source file.
  588.  
  589. The current release and additional information about this software can be 
  590. found starting at: http://www.cc.gatech.edu/gvu/ui/sub_arctic/
  591.  
  592. ========================================================================*/
  593.